<template>
  <div id="app">
    <router-view />
    <div v-if="showKschBtn" class="lyBtn">
      <a-button v-if="chrsType" round type="primary" style="height: 28px" @click="showLy = true">{{
        formattedTime
      }}</a-button>
      <a-button v-else round type="primary" style="height: 28px" @click="openClick" :loading="loadingObj.kschBtn">开始晨会
      </a-button>
    </div>
    <!-- 参会人数 -->
    <van-dialog class="dial" v-model="isShowDialog" :show-confirm-button="false">
      <van-field class="van-field_style" v-if="upType == 'chrs'" v-model="joinUserNumber" clearable label="参会人数"
        placeholder="请输入参会人数" :error-message="errorMessage" @blur="validateNumber" @input="clearError" />
      <div class="iconStyle" v-if="upType !== 'chrs'">
        <van-icon v-if="upType !== 'bcly'" :class="upType == 'scsb' ? 'scsbIcon' : 'sccgIcon'"
          :name="upType == 'scsb' ? 'close' : 'passed'" />
        <div class="tips">{{ tipContent }}</div>
      </div>
      <div class="btnStyleDialog">
        <van-button v-if="upType == 'bcly' || upType == 'chrs'" type="default" style="margin-right: 10px"
          @click="handleCancelDialog">取消</van-button>
        <div v-if="upType == 'scsb'" style="display: flex">
          <van-button style="margin-right: 10px" type="default" @click="handleReturnLy">返回</van-button>
          <a-button class="btnConfirm" type="danger" :loading="loadingObj.reUploadBtn" @click="recStop(true)">
            重新上传
          </a-button>
        </div>
        <a-button v-if="upType == 'sccg' || upType == 'bcly' || upType == 'chrs'" class="btnConfirm" type="primary"
          :loading="loadingObj.comfirmBtn" @click="handleConfirm">
          确定
        </a-button>
      </div>
    </van-dialog>
    <!-- 录音组件 -->
    <van-action-sheet class="actiob_sheet" v-model="showLy">
      <div class="action-sheet-header" @touchstart="handleTouchStart" @touchmove="handleTouchMove"
        @touchend="handleTouchEnd">
        <div style="height: 4px; width: 28px; background: #e0e0e0; margin: 10px auto 0; border-radius: 20px"></div>
      </div>
      <div class="action-sheet-content">
        <div class="lyContent" style="padding: 14px">
          <div class="lyTime">{{ formattedTime }}</div>
          <div class="tools" style="display: flex; justify-content: space-around; margin-top: 10px">
            <a-button class="btnStyle" type="danger" @click="recStop(true)" :loading="loadingObj.uploadBtn"
              :disabled="hasSaveAudio">
              结束并上传
            </a-button>
            <van-button class="btnStyle" plain type="info" @click="resetRecording"> 重新录音 </van-button>
          </div>
        </div>
      </div>
    </van-action-sheet>
    <!-- 提示屏幕信息 -->
    <van-dialog class="tipsScreen" v-model="isShowTip" :show-confirm-button="false">
      <div class="iconStyle">
        <van-icon name="info-o" class="infoIcon" />
        <div class="tips">开始录音后，请保持屏幕常亮！监测到应用切换后台、锁屏、接听电话后，录音将自动暂停！</div>
      </div>
      <div class="btnStyleDialog">
        <a-button class="btnConfirm" type="primary" @click="keepLy">
          {{ isRecording ? '继续录音' : '确定' }}
        </a-button>
      </div>
    </van-dialog>
  </div>
</template>
<script>
import { Toast, Dialog, Notify } from 'vant'
import zhCN from 'ant-design-vue/lib/locale-provider/zh_CN'
import { postAction, sql2apiAction, getAction, uploadAction } from '@api/manage'
import Recorder from 'recorder-core'

//引入mp3格式支持文件；如果需要多个格式支持，把这些格式的编码引擎js文件放到后面统统引入进来即可
import 'recorder-core/src/engine/mp3'
import 'recorder-core/src/engine/mp3-engine'
export default {
  data() {
    return {
      locale: zhCN,
      startY: 0,
      isTouching: false,
      touchStartY: 0,
      touchMoveY: 0,
      showKschBtn: false,
      showLy: false,
      isShowDialog: false,
      upType: 'chrs',
      joinUserNumber: '',
      errorMessage: '',
      startTime: 0,
      elapsedTime: 0,
      timer: null,
      recorder: null,
      hasSaveAudio: false,
      loadingObj: {
        kschBtn: false,
        uploadBtn: false,
        comfirmBtn: false,
        reUploadBtn: false,
      },
      isLoadingLy: false,
      tipLoading: '正在加载录音',
      lastUploadTime: 0,
      chrsType: false,
      // 新增：5秒打印相关变量
      lastPrintTime: 0,
      printInterval: 5000, // 5秒
      pendingFrames: [], // 暂存的音频帧
      send_logNumber: 0,
      testFrames: [],
      testRec: null,
      mergeBlob: null,
      testUseMerge: true, // 是否合并成一个完整音频
      isLy: '',
      queryParam: {
        gridCode: '',
      },
      isShowTip: false,
      isRecording: false,
      mediaStream: null,
      iosTimer: 0
    }
  },
  computed: {
    formattedTime() {
      const totalSeconds = Math.floor(this.elapsedTime / 1000)
      const hours = Math.floor(totalSeconds / 3600)
        .toString()
        .padStart(2, '0')
      const minutes = Math.floor((totalSeconds % 3600) / 60)
        .toString()
        .padStart(2, '0')
      const seconds = (totalSeconds % 60).toString().padStart(2, '0')
      return `${hours}:${minutes}:${seconds}`
    },
    tipContent() {
      switch (this.upType) {
        case 'bcly':
          return '确认保存录音并退出'
        case 'scsb':
          return '录音上传失败'
        case 'sccg':
          return '录音已上传成功'
      }
    }
  },
  watch: {
    '$route.path': {
      handler(newPath) {
        this.isShowDialog = false
        this.showLy = false
        this.$nextTick(() => {
          let pageType = localStorage.getItem('goDetailType')
          this.showKschBtn = newPath.includes('/publicline/morning') && pageType == 'morning' // 替换为你的指定页面路径
          if (!this.showKschBtn) {
            this.recClose()
            this.chrsType = false
            this.joinUserNumber = ''
            this.upType = 'chrs'
            this.isShowDialog = false
            this.showLy = false
            this.elapsedTime = 0
            this.iosTimer = 0
            this.stopTimer()
            this.removeVisibilityListener()
            localStorage.removeItem('goDetailType')
          } else {
            //屏幕常亮
            this.startKeepRecord()
            // 在录音页面时设置监听
            this.setupVisibilityListener()
          }
        })
      },
      immediate: true, // 立即执行一次
    },
  },
  created() {
    this.Rec = Recorder
  },
  mounted() {
    // 确保在组件挂载时设置监听
    this.setupVisibilityListener()
  },
  beforeDestroy() {
    this.removeVisibilityListener()
  },
  methods: {
    handleTouchStart(event) {
      this.isTouching = true
      this.touchStartY = event.touches[0].clientY
    },
    handleTouchMove(event) {
      if (!this.isTouching) return
      this.touchMoveY = event.touches[0].clientY
      const deltaY = this.touchMoveY - this.touchStartY

      // 如果向下滑动超过一定距离，隐藏 Action Sheet
      if (deltaY > 20) {
        this.showLy = false
      }
    },
    handleTouchEnd() {
      this.isTouching = false
    },
    startKeepRecord() {
      this.clearKeepRecord() // 保险：先清一次
      this.keepLightTimer = setInterval(this.keepScreenAwake, 5000)
    },
    clearKeepRecord() {
      if (this.keepLightTimer) {
        clearInterval(this.keepLightTimer)
        // this.keep = null;
      }
    },
    async keepScreenAwake() {
      try {
        // 尝试获取屏幕唤醒锁
        if ('wakeLock' in navigator) {
          this.wakeLock = await navigator.wakeLock.request('screen')
          console.log('屏幕常亮已启用')

          // 处理屏幕锁释放事件
          this.wakeLock.addEventListener('release', () => {
            console.log('屏幕唤醒锁已释放')
          })
        } else {
          console.warn('当前浏览器不支持屏幕常亮功能')
          // this.showWakeLockInstructions();
        }
      } catch (err) {
        console.error(`启用屏幕常亮失败: ${err.message}`)
      }
    },
    setupVisibilityListener() {
      document.addEventListener('visibilitychange', this.handleVisibilityChange)
    },

    removeVisibilityListener() {
      document.removeEventListener('visibilitychange', this.handleVisibilityChange)
    },

    handleVisibilityChange() {
      console.log('隐藏ddd 页面进入后台，暂停录音=', document.hidden)
      console.log('显示xs 页面在前台，录音=', document.visible)
      console.log('显示录音状态=', this.isRecording)
      // 只有在录音页面且正在录音时才处理
      if (!this.showKschBtn || !this.isRecording) return

      if (document.visibilityState === 'hidden') {
        console.log('页面切换到后台，暂停录音')
        this.recPause()
        this.isShowTip = true
        // this.isRecording = false
      } else if (document.visibilityState === 'visible') {
        console.log('页面恢复显示')
        if (this.isRecording) {
          this.isShowTip = true
        } else {
          this.isShowTip = false
        }
      }
    },
    keepLy() {
      this.isShowTip = false
      if (!this.isRecording) {
        if (this.iosTimer > 0) {
          this.continueStartLy(this.iosTimer)
        } else {
          this.newStartLy()
        }
      } else {
        this.recResume()
      }
    },
    openClick() {
      let app_version = process.env.VUE_APP_VERSION
      this.queryParam.gridCode = localStorage.getItem('$gridId')
      let params = {
        grId: this.queryParam.gridCode,
        type: 1,
        version: app_version,
      }
      this.loadingObj.kschBtn = true
      this.isRecording = false
      getAction('/common/sound/recording/checkIsSupportSoundRecording', { ...params })
        .then((res) => {
          this.loadingObj.kschBtn = false
          this.loadingObj.uploadBtn = false
          this.elapsedTime = 0
          this.hasSaveAudio = false

          if (res.code == 200) {
            if (res.result) {
              this.showLy = true
              this.isLoadingLy = false
              //回显保存的录音
              if (res.result.state == 1) {
                this.elapsedTime = res.result.costTime * 1000 || 0
                this.hasSaveAudio = true
                this.stopTimer()
              } else if (res.result.state == 0) {
                this.isShowTip = true
                this.elapsedTime = res.result.costTime * 1000 || 0
                this.iosTimer = JSON.parse(JSON.stringify(this.elapsedTime))
                this.stopTimer()
              } else {
                this.isShowTip = true
                // this.newStartLy()
              }
            } else {
              if (!this.chrsType) {
                this.showLy = false
                this.isShowDialog = true
                this.upType = 'chrs'
              } else {
                this.showLy = true
              }
            }
          } else {
            this.$toast(res.message)
          }
        })
        .catch((err) => {
          this.loadingObj.kschBtn = false
          this.$toast(err.message)
        })
    },
    validateNumber() {
      if (!this.joinUserNumber) {
        this.errorMessage = '请输入参会人数'
        return false
      }

      // 使用正则验证是否为正整数
      const reg = /^[1-9]\d*$/
      if (!reg.test(this.joinUserNumber)) {
        this.errorMessage = '请输入有效的正整数'
        return false
      }

      this.errorMessage = ''
      return true
    },
    clearError() {
      if (this.errorMessage) {
        this.errorMessage = ''
      }
    },
    handleConfirm() {
      if (this.upType == 'sccg') {
        this.isShowDialog = false
        this.showLy = false
        this.recorder = null
        this.elapsedTime = 0
      }
      // if (this.upType == 'bcly') {
      //   this.stopRecording('false')
      // }
      if (this.upType == 'chrs') {
        this.validateNumber()
        if (!this.errorMessage && this.joinUserNumber) {
          let params = {
            grId: this.queryParam.gridCode,
            type: 1,
            joinUserNumber: parseInt(this.joinUserNumber),
          }
          this.loadingObj.comfirmBtn = true
          getAction('/common/sound/recording/joinUserNumberSubmit', { ...params })
            .then((res) => {
              if (res.code == 200) {
                this.showLy = true
                this.isShowDialog = false
                //先显示提示 确定之后再开始录音
                this.isShowTip = true
                // this.newStartLy()
              } else {
                this.upType = 'chrs'
                this.joinUserNumber = ''
                this.$toast(res.message)
              }
              this.loadingObj.comfirmBtn = false
            })
            .catch((err) => {
              this.upType = 'chrs'
              this.joinUserNumber = ''
              this.$toast(err.message)
              this.loadingObj.comfirmBtn = false
            })
        }
      }
    },
    async recClose() {
      var rec = this.rec;
      console.log("🚀close ~ rec:", rec)
      this.rec = null;
      console.log("🚀 ~close this.rec:", this.rec)
      this.isRecording = false;

      if (rec) {
        try {
          // 1. 先停止录音
          console.log("🚀 ~ Recorder.IsOpen():", Recorder.IsOpen())
          if (Recorder.IsOpen()) {
            await new Promise(resolve => rec.stop(resolve));
          }

          // 2. 关闭Recorder实例
          rec.close();

          // 3. 关闭AudioContext（如果有）
          if (rec.context) {
            await rec.context.close();
          }

          // 4. 清理媒体轨道
          if (this.mediaStream) {
            this.mediaStream.getTracks().forEach(track => track.stop());
            this.mediaStream = null;
          }

          // 5. 重置所有相关引用
          this.testRec = null;
          console.log("录音已完全关闭");
        } catch (err) {
          console.error("关闭过程中出错:", err);
        }
      }
    },
    //开始录音
    newStartLy() {
      if (this.isInCall('0')) {
        this.handleCallState()
        return
      }
      if (this.rec) {
        console.log('已有录音在进行中，无法重复开始')
        this.recClose()
      }
      console.log('navigator', navigator)
      // 检查麦克风权限
      navigator.mediaDevices
        .getUserMedia({ audio: true })
        .then((stream) => {
          // 检查设备是否在通话中（iOS特殊处理）
          // 检查音频轨道是否被占用（通话中）
          const audioTracks = stream.getAudioTracks()
          console.log('🚀 ~ audioTracks:', audioTracks)
          if (audioTracks.length === 0 || !audioTracks[0].enabled) {
            this.handleCallState()
            stream.getTracks().forEach((track) => track.stop())
            return
          }

          var This = this
          var rec = (this.rec = Recorder({
            type: 'mp3',
            sampleRate: 16000, // 设置采样率为8000khz
            // bitDepth: 8, // 设置位深为8
            bitRate: 16, // 设置比特率为16kbps
            // onProcess: function (buffers, powerLevel, duration, sampleRate) {
            //   // 实时检查通话状态
            //   if (This.isInCall()) {
            //     This.handleCallState()
            //     return
            //   }
            // },
            takeoffEncodeChunk: function (chunkBytes) {
              // This.RealTimeSendTry(chunkBytes, false)
              if (!This.isInCall()) {
                This.RealTimeSendTry(chunkBytes, false)
              }
            },
          }))
          rec.open((err) => {
            if (err) {
              console.error('无法录音：', err)
              this.$toast(`请授权麦克风权限！`)
            } else {
              this.chrsType = true
              this.lastUploadTime = 0 // 初始化上传时间戳
              console.log('录音准备就绪')
              this.startTime = Date.now()
              this.elapsedTime = 0
              rec.start()
              this.startTimer()
              this.isRecording = true
              // 保存stream引用以便后续检查
              this.mediaStream = stream

              // 监听音频轨道状态变化
              this.setupAudioTrackMonitoring(stream)
            }
          })
          this.testRec = rec
          this.testFrames = []
          // this.testDuration = 0
          this.RealTimeSendReset()
        })
        .catch((err) => {
          console.error('麦克风权限未授权：', err)
          this.$toast(`请授权麦克风权限！`)
        })
      console.log("🚀 ~ navigator:", navigator)
    },
    async continueStartLy(timesNum) {
      this.isRecording = false
      console.log('继续开始录音')
      if (this.isInCall('0')) {
        this.handleCallState()
        return
      }
      console.log("🚀 ~ this.rec-continueStartLy:", this.rec)
      if (this.rec) {
        console.log('录音正在进行中或未完全关闭');
        this.rec.stop()
      }
      // if (this.rec ) {
      //   console.log('录音正在进行中或未完全关闭');
      //   await this.recClose(); // 等待完全关闭
      //   await new Promise(resolve => setTimeout(resolve, 100)); // 添加短暂延迟
      // }
      setTimeout(() => {
        console.log('延时处理，继续开始录音')
        // 检查麦克风权限
        navigator.mediaDevices
          .getUserMedia({ audio: true })
          .then((stream) => {
            // 检查设备是否在通话中（iOS特殊处理）
            // 检查音频轨道是否被占用（通话中）
            const audioTracks = stream.getAudioTracks()
            if (audioTracks.length === 0 || !audioTracks[0].enabled) {
              this.handleCallState()
              stream.getTracks().forEach((track) => track.stop())
              return
            }

            var This = this
            var rec = (this.rec = Recorder({
              type: 'mp3',
              sampleRate: 16000, // 设置采样率为8000khz
              // bitDepth: 8, // 设置位深为8
              bitRate: 16, // 设置比特率为16kbps
              onProcess: function (buffers, powerLevel, duration, sampleRate) {
                // 实时检查通话状态
                // if (This.isInCall()) {
                //   This.handleCallState()
                //   return
                // }
              },
              takeoffEncodeChunk: function (chunkBytes) {
                console.log('This.isInCall', This.isInCall())
                // if (!This.isInCall()) {
                  This.RealTimeSendTry(chunkBytes, false)
                // }
              },
            }))
            console.log("🚀 ~ rec:", rec)

            rec.open((err) => {
              if (err) {
                console.error('无法录音：', err)
                this.$toast(`请授权麦克风权限！`)
              } else {
                this.chrsType = true
                this.lastUploadTime = 0 // 初始化上传时间戳
                console.log('录音准备就绪')
                // this.startTime = Date.now()
                this.startTime = Date.now() - timesNum
                this.elapsedTime = 0
                rec.start()
                this.startTimer()
                this.isRecording = true
                // 保存stream引用以便后续检查
                this.mediaStream = stream

                // 监听音频轨道状态变化
                this.setupAudioTrackMonitoring(stream)
              }
            })
            this.testRec = rec
            this.testFrames = []
            // this.testDuration = 0
            this.RealTimeSendReset()
          })
          .catch((err) => {
            console.error('麦克风权限未授权：', err)
            this.$toast(`请授权麦克风权限！`)
          })
      }, 1000);

    },
    startTimer() {
      this.stopTimer()
      this.timer = setInterval(() => {
        this.elapsedTime = Date.now() - this.startTime
        this.iosTimer = JSON.parse(JSON.stringify(this.elapsedTime))
        // 每5秒检查一次通话状态
        if (this.elapsedTime % 5000 < 100) {
          if (this.isInCall()) {
            this.handleCallState()
          }
        }
      }, 1000)
    },

    stopTimer() {
      if (this.timer) {
        clearInterval(this.timer)
        this.timer = null
      }
    },
    recPause: function () {
      if (this.rec && Recorder.IsOpen()) {
        this.stopTimer()
        this.rec.pause()
      } else {
        console.log('暂停录音--未打开录音', this.rec)
      }
    },
    recResume: function () {
      console.log('继续录音')
      if (this.rec && Recorder.IsOpen()) {
        this.startTime = Date.now() - this.elapsedTime
        this.startTimer()
        this.rec.resume()
      } else {
        console.log('继续录音--未打开录音', this.rec)
      }
    },
    recStop: function (type) {
      if (this.elapsedTime == 0) {
        this.$toast('请录音后再上传!')
        this.loadingObj.uploadBtn = false
        this.loadingObj.reUploadBtn = false
        return
      }
      //检查网络是否可用
      // this.isLoadingLy = true
      // this.tipLoading = '正在检测网络vpn...'
      this.loadingObj.uploadBtn = type
      this.loadingObj.reUploadBtn = type
      this.stopTimer()
      if (!(this.rec && Recorder.IsOpen())) {
        console.log('🚀 ~ 未打开录音:=', '未打开录音')
        return
      }

      var This = this
      var rec = This.rec
      var stopNext = function () {
        This.RealTimeSendTry(new Uint8Array(0), type) //最后一次发送
      }

      rec.stop(
        function (blob, duration) {
          stopNext()
          This.recClose()
        },
        function (s) {
          stopNext()
          console.log("🚀 ~ '录音失败：==':", '录音失败：')
        }
      )
    },
    // 处理通话状态
    handleCallState() {
      console.error("🚀 ~ methods.handleCallState:")
      if (this.isRecording) {
        // 停止当前录音
        console.log('🚀 ~ 需要停止当前录音:')
        // this.stopRecording();

        // 显示通话提示
        // this.$toast({
        //   message: '检测到ios设备正在通话，录音已被结束',
        //   duration: 3000,
        //   position: 'middle',
        // })
        // this.$toast('检测到ios设备录音被占用，录音已被停止，请再次录音!')
        // Toast.fail('检测到ios设备录音被占用，录音已被停止，请再次录音!')
        this.recStop(false)
        // this.recPause()

        Dialog.alert({
          title: '录音被占用',
          message: '检测到ios设备录音被占用，录音已被停止，请继续录音!',
          confirmButtonText: '继续录音'
        }).then(() => {
          // location.reload()
          this.loadingObj.uploadBtn = false
          this.loadingObj.reUploadBtn = false
          this.continueStartLy(this.iosTimer)
          // this.recResume()
        })
        // 提供重新录音的选项
        setTimeout(() => {
          console.log('🚀 ~ 通话已结束，是否重新开始录音？:')
          // location.reload()
          // if (confirm('通话已结束，是否重新开始录音？')) {
          //   this.restartRecording();
          // }
        }, 1500)
      } else {
        this.$toast('设备正在通话中，请结束通话后录音')
      }
    },

    isInCall(type) {
      if(type) {
        return false
      }

      if(window.__callState) {
        return true
      }

      return false
    // 检查是否在通话中
      // iOS设备检测通话状态
      if (navigator.userAgent.match(/iPhone|iPad|iPod/i)) {
        // 方法1：检查设备能力（有限制）
        if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
          // 通过尝试获取麦克风状态来判断
          return false // 这里需要结合其他方法
        }

        // 方法2：通过用户代理字符串检测（辅助方法）
        // 注意：这种方法不完全可靠
      }

      // 通用方法：检查网络连接类型（通话时可能切换到2G/3G）
      const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection
      if (connection && connection.type) {
        const cellularTypes = ['cellular', '2g', '3g', '4g']
        if (cellularTypes.includes(connection.type) && connection.downlink < 0.1) {
          return true // 可能正在通话
        }
      }

      return false
    },

    // 设置音频轨道监控
    setupAudioTrackMonitoring(stream) {
      const audioTracks = stream.getAudioTracks()
      console.log("🚀 ~ 轨道监控audioTracks:", audioTracks)
      if (audioTracks.length > 0) {
        audioTracks[0].addEventListener('ended', () => {
          console.log('音频轨道已结束（可能因为通话）')
          this.handleCallState()
        })

        audioTracks[0].addEventListener('mute', () => {
          console.log('音频轨道被静音（可能因为通话）')
          if (this.isRecording) {
            this.handleCallState()
          }
        })
      }
    },
    // 处理录音错误
    handleRecorderError(err) {
      console.error('录音错误:', err)

      if (err.name === 'NotAllowedError') {
        this.$toast('请授权麦克风权限！')
      } else if (err.name === 'NotFoundError') {
        this.$toast('找不到麦克风设备')
      } else if (err.name === 'NotReadableError') {
        this.$toast('麦克风被其他应用占用，请检查是否在通话中')
      } else {
        this.$toast('录音失败，请检查设备状态')
      }
    },
    RealTimeSendReset: function () {
      this.send_frameBuffer = new Uint8Array(0)
      this.send_logNumber = 0
      this.lastPrintTime = Date.now()
      this.pendingFrames = []
    },
    RealTimeSendTry: function (chunkBytes, isClose) {
      // 将数据添加到暂存队列
      if (chunkBytes.length > 0) {
        this.pendingFrames.push(new Uint8Array(chunkBytes))
      }

      // 获取当前时间戳
      const now = Date.now()
      const timeInterval = now - this.lastPrintTime

      // 如果是关闭录音或者时间间隔达到5秒，则进行打印
      if (isClose || timeInterval >= this.printInterval) {
        console.error('进入合并数据帧', timeInterval)
        // 合并所有暂存的帧数据
        this.mergeAndPrintFrames(isClose)
        this.lastPrintTime = now
      }
    },

    // 新增：合并并打印暂存的帧数据
    mergeAndPrintFrames: function (type) {
      if (this.pendingFrames.length === 0) return

      // 计算所有帧的总大小
      let totalSize = 0
      for (let i = 0; i < this.pendingFrames.length; i++) {
        totalSize += this.pendingFrames[i].length
      }

      // 合并所有帧
      const mergedBytes = new Uint8Array(totalSize)
      let offset = 0
      for (let i = 0; i < this.pendingFrames.length; i++) {
        mergedBytes.set(this.pendingFrames[i], offset)
        offset += this.pendingFrames[i].length

        // 如果需要保存到测试帧中用于后续合并
        if (this.testUseMerge) {
          this.testFrames.push(this.pendingFrames[i])
        }
      }

      // 打印合并后的数据
      const number = ++this.send_logNumber
      this.testLogFrame(mergedBytes, number, type)

      // 清空暂存队列
      this.pendingFrames = []
    },
    testLogFrame: function (frameBytes, number, type) {
      var recSet = this.rec.set
      var dur = 0 //简单估算数据时长，不一定准确
      dur = Math.round((frameBytes.length / recSet.bitRate) * 8)

      var blob = new Blob([frameBytes.buffer], { type: 'audio/' + recSet.type })
      var logMsg = 'No.' + (number < 100 ? ('000' + number).substr(-3) : number)

      var form = new FormData()
      form.append('file', blob, 'recorder.mp3') //和普通form表单并无二致，后端接收到upfile参数的文件，文件名为recorder.mp3
      form.append('grId', localStorage.getItem('$gridId'))
      form.append('isFinish', type ? 'true' : 'false') //是否是最后一块数据

      uploadAction('/common/sound/recording/uploadLiveFile', form, 300000)
        .then((response) => {
          const { result, code } = response
          this.isLoadingLy = false
          this.loadingObj.uploadBtn = false
          this.loadingObj.reUploadBtn = false
          if (type) {
            if (code == 200) {
              this.upType = 'sccg'
              this.isShowDialog = true
              this.chrsType = false
              this.showLy = false
              this.recorder = null
              this.isRecording = false
            } else {
              this.$toast(response.message)
              this.upType = 'scsb'
              this.showLy = false
              this.isShowDialog = true
              this.loadingObj.reUploadBtn = false
            }
          } else {
            if (code !== 200) {
              this.$toast(response.message)
            }
            this.showLy = true
            this.loadingObj.uploadBtn = false
            this.loadingObj.reUploadBtn = false
          }
        })
        .catch((err) => {
          this.isLoadingLy = false
          this.loadingObj.uploadBtn = false
          this.loadingObj.reUploadBtn = false
          if (type == 'true') {
            this.$toast('上传出错：' + err.message)
            this.upType = 'scsb'
            this.showLy = false
            this.isShowDialog = true
          }
        })
    },

    async resetRecording() {
      // 重新录音功能应该是先本次停止录音，然后再重新开始录音
      // 没有这段代码的话，点击重新录音之后，录音上传不会停止
      this.recStop()
      this.isRecording = false
      this.stopTimer()
      this.elapsedTime = 0
      this.iosTimer = 0
      //有保存录音的情况
      this.getRest()
    },
    getRest() {
      getAction(`/common/sound/recording/reRecord?grId=${this.queryParam.gridCode}`)
        .then((res) => {
          this.hasSaveAudio = false
          this.isShowTip = true
          // this.newStartLy()
        })
        .catch((err) => {
          this.$toast(err.message)
        })
    },
    handleCancelDialog() {
      if (this.upType == 'chrs') {
        this.joinUserNumber = ''
        this.isShowDialog = false
        this.showLy = false
      } else {
        this.joinUserNumber = ''
        this.isShowDialog = false
        this.showLy = true
        // this.recorder = null
      }
    },
    handleReturnLy() {
      this.showLy = true
      this.isShowDialog = false
      this.loadingObj.uploadBtn = false
      this.loadingObj.reUploadBtn = false
      this.isLoadingLy = false
    },
  },
}
</script>
<style lang="less">
#app {
  background: #f3f7fa;
  font-size: 14px;
  min-height: 100vh;
  color: #000;
  /* width: 100vw;
  position: absolute; */
}

.app-page {
  min-height: 100%;
}

/* .van-tabs {
  height: 100%;
} */
/* .van-tabs__content {
  min-height: 400px;
} */
.lyBtn {
  position: fixed;
  bottom: 10px;
  left: 0;
  width: 100%;
  z-index: 9;
  text-align: center;

  .ant-btn-primary {
    border-radius: 20px;
    height: 28px;
    background: linear-gradient(134deg, #7acbf9 0%, #5a75fa 100%);
    border: 0;
  }
}

.lyContent {
  text-align: center;

  .lyTime {
    font-size: 30px;
    font-weight: bold;
    height: 120px;
    line-height: 120px;
  }

  .actions {
    font-size: 50px;
    color: #1989fa;
    margin-bottom: 10px;
    cursor: pointer;
  }

  .tips {
    color: #969799;
    font-size: 14px;
    margin-bottom: 10px;
  }

  .tools {
    .btnStyle {
      border-radius: 8px;
      height: 36px;
    }

    .plain-btn {
      padding: 6px 12px;
      font-size: 14px;
      border: 1px solid #1989fa;
      color: #1989fa;
      background: transparent;
      border-radius: 8px;
      cursor: pointer;
    }

    .plain-btn:active,
    .plain-btn:hover,
    .plain-btn:focus {
      /* 强制所有状态保持同一样式 */
      background: transparent !important;
      color: #1989fa !important;
      border-color: #1989fa !important;
      outline: none;
    }

    .plain-btn:disabled {
      opacity: 0.4;
      cursor: not-allowed;
    }

    // /deep/ .van-button{
    //   border-radius: 8px;
    //   height: 36px;
    // }
  }
}

.tipsScreen {
  .van-dialog__content {
    padding: 10px 14px;
  }
}

.btnStyleDialog {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 20px;

  .van-button {
    border-radius: 6px;
    height: 32px;
    width: 114px;
  }

  .ant-btn {
    border-radius: 6px;
    height: 32px;
    width: 114px;
  }
}

.iconStyle {
  text-align: center;

  .scsbIcon {
    color: #ff4d4f;
    font-size: 48px;
    margin-bottom: 10px;
  }

  .sccgIcon {
    color: #52c41a;
    font-size: 48px;
    margin-bottom: 10px;
  }

  .infoIcon {
    color: #d6c066;
    font-size: 48px;
    margin-bottom: 10px;
  }

  .tips {
    margin-bottom: 14px;
    font-family: SourceHanSansCN-Regular;
    font-size: 14px;
    color: #333333;
    text-align: center;
    line-height: 21px;
    font-weight: 400;
  }
}

.van-field_style {
  padding: 20px;

  .van-cell__title .van-field__label {
    font-family: SourceHanSansCN-Regular;
    font-size: 14px;
    color: #333333;
    line-height: 24px;
    font-weight: 400;
  }

  .vant-field__value {
    background: rgba(204, 204, 204, 0.1);
    border-radius: 4px;
  }
}

.dial {
  width: 300px;

  .van-dialog__content {
    padding: 26px 14px;
  }
}
</style>